unit ResultsGui;

interface

uses
  InventionCalc, GlobalRecordsAndEnums, Items, Results,
  AddConfigurationGui, RemoveResultsGui,

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, Buttons;

type
  TfrmResults = class(TForm)
    lstItems: TListView;
    lstConfigurations: TListView;
    gbResultSummary: TGroupBox;
    lblDecryptor: TLabel;
    lblMetaLevel: TLabel;
    lblBPCRuns: TLabel;
    lblLocation: TLabel;
    lblSuccesses: TLabel;
    lblFailures: TLabel;
    lblSuccessPercentage: TLabel;
    btnRemoveResult: TButton;
    lblBPCME: TLabel;
    lblBPCPE: TLabel;
    lblExpectedPercentage: TLabel;
    lblAmount: TLabel;
    btnApplyFilter: TSpeedButton;
    btnClose: TButton;
    lblBPCMaxRuns: TLabel;
    lblResultDecryptor: TLabel;
    lblResultMetaLevel: TLabel;
    lblResultBPCMaxRuns: TLabel;
    lblResultBPCRuns: TLabel;
    lblResultBPCPE: TLabel;
    lblResultLocation: TLabel;
    lblResultAmount: TLabel;
    lblResultSuccesses: TLabel;
    lblResultFailures: TLabel;
    lblResultSuccessPercentage: TLabel;
    lblResultExpectedPercentage: TLabel;
    btnAddConfiguration: TButton;
    Label1: TLabel;
    lblResultBPCME: TLabel;
    lblItem: TLabel;
    lblConfiguration: TLabel;
    lblResultItem: TLabel;
    lblResultConfiguration: TLabel;
    btnHelp: TButton;
    procedure btnCloseClick(Sender: TObject);
    procedure lstItemsChange(Sender: TObject; Item: TListItem;
      Change: TItemChange);
    procedure lstConfigurationsDblClick(Sender: TObject);
    procedure lstConfigurationsChange(Sender: TObject; Item: TListItem;
      Change: TItemChange);
    procedure btnAddConfigurationClick(Sender: TObject);
    procedure btnRemoveResultClick(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure btnApplyFilterClick(Sender: TObject);
    procedure lstConfigurationsColumnClick(Sender: TObject;
      Column: TListColumn);
    procedure lstConfigurationsCompare(Sender: TObject; Item1, Item2: TListItem;
      Data: Integer; var Compare: Integer);
    procedure btnHelpClick(Sender: TObject);
  private
    inventionCalc: TInventionCalc;
    configurationresultlist: SConfigurationResultList; // cached version of all results and configurations of the currently selected item.

    sortcolumn: Integer;
    sortdirection: boolean;


    procedure LoadItems;
    procedure LoadConfigurations;

    function GetConfigurations(list: TResultsList; item: TNewItem): SConfigurationResultList;
  public
    constructor Create(AOwner: TComponent; invCalc: TInventionCalc); reintroduce;
  end;

var
  frmResults: TfrmResults;

implementation

uses
  Category, MainGui, ExtActns;

{$R *.dfm}

constructor TfrmResults.Create(AOwner: TComponent; invCalc: TInventionCalc);
begin
  Inherited Create(AOwner);
  inventionCalc := invCalc;

  sortcolumn := inventionCalc.UserSettings.Settings.ResultsConfigurationSortColumn;
  if (sortcolumn < 0) then sortcolumn := 0;
  sortdirection := inventionCalc.UserSettings.Settings.ResultsConfigurationSortDirection;

  btnApplyFilter.Down := inventionCalc.UserSettings.Settings.ResultFilterItems;
  LoadItems;
end;

procedure TfrmResults.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  inventionCalc.Results.Save;
end;

procedure TfrmResults.LoadItems;
var
  i: Integer;
  item: TListItem;
  list: TNewItemsList;
  allowedtoadd: Boolean;
begin
  lstItems.Clear;
  lstConfigurations.Clear;
  list := inventionCalc.Results.GetResultItems;
  for i := 0 to Length(list) -1 do begin
    if (not btnApplyFilter.Down) then begin
      item := lstItems.Items.Add;
      item.Caption := list[i].Name;
      item.Data := list[i];
    end
    else begin
      if (list[i].Category <> nil) then begin
        allowedtoadd := MainGui.categories.IndexOf(list[i].Category) >= 0;
        if (list[i].Subcategory <> nil) then allowedtoadd := ((allowedtoadd) and (subcategories.IndexOf(list[i].Subcategory) >= 0));
        if (list[i].Group <> nil) then allowedtoadd := ((allowedtoadd) and (groups.IndexOf(list[i].Group) >= 0));
        if (list[i].InventionRace = Amarr) then allowedtoadd := (allowedtoadd and inventionCalc.UserSettings.Settings.FilterAmarr)
        else if (list[i].InventionRace = Caldari) then allowedtoadd := (allowedtoadd and inventionCalc.UserSettings.Settings.FilterCaldari)
        else if (list[i].InventionRace = Gallente) then allowedtoadd := (allowedtoadd and inventionCalc.UserSettings.Settings.FilterGallente)
        else if (list[i].InventionRace = Minmatar) then allowedtoadd := (allowedtoadd and inventionCalc.UserSettings.Settings.FilterMinmatar);
        if (allowedtoadd) then begin
          item := lstItems.Items.Add;
          item.Caption := list[i].Name;
          item.Data := list[i];
        end;
      end;
    end;
  end;
  lstItems.AlphaSort;
end;

procedure TfrmResults.LoadConfigurations;
var
  i: Integer;
  listitem: TListItem;
begin
  lstConfigurations.Clear;
  if (lstItems.Selected <> nil) then begin
//    resultlist := inventionCalc.Results.GetResults(TNewItem(lstItems.Selected.Data));
    configurationresultlist := GetConfigurations(inventionCalc.Results.GetResults(TNewItem(lstItems.Selected.Data)), TNewItem(lstItems.Selected.Data));
    for i := 0 to Length(configurationresultlist) -1 do begin
      listitem := lstConfigurations.Items.Add;
      listitem.Caption := configurationresultlist[i].Configuration.Name;
      listitem.SubItems.Add(IntToStr(configurationresultlist[i].Amount));
      listitem.SubItems.Add(FloatToStrF(configurationresultlist[i].SuccessPercentage * 100, ffNumber, 5, 2));
      listitem.Data := configurationresultlist[i].Configuration;
    end;
  end;
  lstConfigurations.AlphaSort;
end;

function TfrmResults.GetConfigurations(list: TResultsList; item: TNewItem): SConfigurationResultList;
// extracts the different configurations and their aggregated success information from the given list of results
// Note that the results in the given list should -all- be for the same item, so fetch the list first using inventionCalc.Results.GetResults
var
  i, j, len: Integer;
  resultitem: TResult;
  alreadyreturned: Boolean;
begin
  SetLength(result, 0);
  for i := 0 to Length(list) -1 do begin
    resultitem := list[i];
    alreadyreturned := false;
    for j := 0 to Length(result) -1 do begin
      if (result[j].Configuration = resultitem.Configuration) then begin
        alreadyreturned := true;
        result[j].Amount := result[j].Amount + 1;
        if (resultitem.Success) then result[j].Successes := result[j].Successes + 1
        else result[j].Failures := result[j].Failures + 1
      end;
    end;
    if (not alreadyreturned) then begin
      len := Length(result);
      SetLength(result, len +1);
      result[len].Configuration := resultitem.Configuration;
      result[len].Amount := 1;
      if (resultitem.Success) then begin
        result[len].Successes := 1;
        result[len].Failures := 0;
      end
      else begin
        result[len].Successes := 0;
        result[len].Failures := 1;
      end;
    end;
  end;
  for i := 0 to Length(result) -1 do begin
    if (result[i].Amount > 0) then
      result[i].SuccessPercentage := result[i].Successes / result[i].Amount
    else
      result[i].SuccessPercentage := 0;
  end;
end;

procedure TfrmResults.btnAddConfigurationClick(Sender: TObject);
var
  gui: TfrmAddConfiguration;
begin
  gui := TfrmAddConfiguration.Create(self, inventionCalc);
  gui.ShowModal;
  gui.Destroy;
end;

procedure TfrmResults.btnApplyFilterClick(Sender: TObject);
begin
  LoadItems;
end;

procedure TfrmResults.btnCloseClick(Sender: TObject);
begin
  inventionCalc.UserSettings.Settings.ResultFilterItems := btnApplyFilter.Down;
  self.Close;
  self.Release;
end;

procedure TfrmResults.btnHelpClick(Sender: TObject);
var
  run: TFileRun;
begin
  run := TFileRun.Create(self);
  run.FileName := 'help\InventionResults.html';
  run.Execute;
  run.Free;
end;

procedure TfrmResults.lstItemsChange(Sender: TObject; Item: TListItem;
  Change: TItemChange);
begin
  if (lstItems.Selected <> nil) then begin
    LoadConfigurations;
  end;
end;

procedure TfrmResults.lstConfigurationsDblClick(Sender: TObject);
var
  s: String;
  config: TConfiguration;
begin
  if (lstConfigurations.Selected <> nil) then begin
    config := TConfiguration(lstConfigurations.Selected.Data);
    s := 'Details for configuration ' + config.Name + ':' + #10#13#10#13;
    if (config.DecryptorType = nil) then s := s + 'Decryptor type: No decryptor' + #10#13
    else s := s + 'Decryptor type: ' + config.DecryptorType.Name + #10#13;
    s := s + 'Meta-item level: ' + IntToStr(config.MetaLevel) + #10#13;
    s := s + 'BPC is max runs: ' + BoolToStr(config.BPCMaxRuns, true) + #10#13;
    s := s + 'BPC runs: ' + IntToStr(config.BPCRuns) + #10#13;
    s := s + 'BPC ME: ' + IntToStr(config.BPCME) + #10#13;
    s := s + 'BPC PE: ' + IntToStr(config.BPCPE) + #10#13;
    s := s + 'Location: ' + config.Location.Name + #10#13;
    MessageDlg(s, mtInformation, [mbOk], 0);
  end;
end;

procedure TfrmResults.lstConfigurationsChange(Sender: TObject;
  Item: TListItem; Change: TItemChange);
var
  i, j: Integer;
  found: Boolean;
  newitem, t1item: TNewItem;
  configresult: SConfigurationResult;
  decrprob: Double;
begin
  if ((lstItems.Selected <> nil) and (lstConfigurations.Selected <> nil)) then begin
    configresult := configurationresultlist[lstConfigurations.ItemIndex];
    if (configresult.Configuration = TConfiguration(lstConfigurations.Selected.Data)) then begin // make sure you have the right configuration
      newitem := TNewItem(lstItems.Selected.Data);
//      gbResultSummary.Caption := 'Result summary for item ' + newitem.Name + ' in configuration ' + configresult.Configuration.Name + ':';
      lblResultItem.Caption := newitem.Name;
      lblResultConfiguration.Caption := configresult.Configuration.Name;

      if (configresult.Configuration.DecryptorType = nil) then lblResultDecryptor.Caption := 'No decryptor'
      else lblResultDecryptor.Caption := configresult.Configuration.DecryptorType.Name;
      lblResultMetaLevel.Caption := IntToStr(configresult.Configuration.MetaLevel);
      lblResultBPCMaxRuns.Caption := BoolToStr(configresult.Configuration.BPCMaxRuns, true);
      if (configresult.Configuration.BPCMaxRuns) then lblResultBPCRuns.Caption := 'Maximum possible'
      else lblResultBPCRuns.Caption := IntToStr(configresult.Configuration.BPCRuns);
      lblResultBPCME.Caption := IntToStr(configresult.Configuration.BPCME);
      lblResultBPCPE.Caption := IntToStr(configresult.Configuration.BPCPE);
      lblResultLocation.Caption := configresult.Configuration.Location.Name;
      lblResultAmount.Caption := IntToStr(configresult.Amount);
      lblResultSuccesses.Caption := IntToStr(configresult.Successes);
      lblResultFailures.Caption := IntToStr(configresult.Failures);
      lblResultSuccessPercentage.Caption := FloatToStrF(configresult.SuccessPercentage * 100, ffNumber, 5, 2) + '%';

      // OMG horrible. But there is no way to link a T2 item to a T1 item, so we have to look it up manually....
      found := false;
      t1item := nil;
      for i := 0 to inventionCalc.GetT1ItemCount -1 do begin
        t1item := inventionCalc.GetT1ItemByIndex(i);
        for j := 0 to t1item.UsedInCount -1 do begin
          if (t1item.GetUsedIn(j).Item = newitem) then begin
            found := true;
            break;
          end;
        end;
        if (found) then break;
      end;
      if (found) then begin
        if (configresult.Configuration.DecryptorType = nil) then decrprob := 1
        else decrprob := configresult.Configuration.DecryptorType.Probability;
        lblResultExpectedPercentage.Caption := FloatToStrF(inventionCalc.UserSettings.Success.GetSuccess(
            t1item.InventionType,
            newitem.BaseChance,
            inventionCalc.UserSettings.Skills.GetSkillLevel(t1item.EncryptionSkill),
            inventionCalc.UserSettings.Skills.GetSkillLevel(t1item.ScienceSkill1),
            inventionCalc.UserSettings.Skills.GetSkillLevel(t1item.ScienceSkill2),
            t1item.Datacore1Amount,
            t1item.Datacore2Amount,
            decrprob,
            configresult.Configuration.MetaLevel
            ) * 100, ffNumber, 5, 2) + '%';
      end;
    end;
  end;
end;

procedure TfrmResults.lstConfigurationsColumnClick(Sender: TObject;
  Column: TListColumn);
begin
  if (sortcolumn = Column.Index) then sortdirection := (not sortdirection)
  else sortdirection := true;

  sortcolumn := Column.Index;
  inventionCalc.UserSettings.Settings.ResultsConfigurationSortColumn := sortcolumn;
  inventionCalc.UserSettings.Settings.ResultsConfigurationSortDirection := sortdirection;
  TListView(Sender).AlphaSort;
end;

procedure TfrmResults.lstConfigurationsCompare(Sender: TObject; Item1,
  Item2: TListItem; Data: Integer; var Compare: Integer);
var
  numsort: Boolean;
begin
  numsort := not (lstConfigurations.Columns[sortcolumn].Caption = 'Configuration');
  Compare := Sort(Item1, Item2, numsort, sortcolumn, sortdirection);
end;

procedure TfrmResults.btnRemoveResultClick(Sender: TObject);
var
  gui: TfrmRemoveResults;
  configresult: SConfigurationResult;
begin
  if ((lstItems.Selected <> nil) and (lstConfigurations.Selected <> nil)) then begin
    configresult := configurationresultlist[lstConfigurations.ItemIndex];
    gui := TfrmRemoveResults.Create(self, inventionCalc, TNewItem(lstItems.Selected.Data), TConfiguration(lstConfigurations.Selected.Data), configresult.Successes, configresult.Failures);
    gui.ShowModal;
    gui.Destroy;
    LoadItems;
  end;
end;


end.
